/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.dess.base.tools.delayed;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Supplier;

/**
 * @project-name:dess
 * @package-name:com.hyts.dess.base.tools
 * @author:LiBo/Alex
 * @create-date:2020-08-11 16:28
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description:
 *
 * DelayQueue类的主要作用：是一个无界的BlockingQueue，用于放置实现了Delayed接口的对象，
 * 其中的对象只能在其到期时才能从队列中取走。这种队列是有序的
 * 即队头对象的延迟到期时间最长。注意：不能将null元素放置到这种队列中。
 *
 * Delayed，一种混合风格的接口，用来标记那些应该在给定延迟时间之后执行的对象。此接口的实现必须定义一个 compareTo 方法，
 * 该方法提供与此接口的getDelay 方法一致的排序。
 */
@Slf4j
public class DelayedQueueUtils {

    /**
     * 延时队列操作控制数据单元
     */
    static DelayQueue<DelayedEvent> queue = new DelayQueue<>();

    /**
     * 线程池执行器操作服务控制对象
     */
    static ExecutorService exec =  new ForkJoinPool(Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory,  null, true);


    /**
     * 支持收入相关的数据对象信息
     * @param delayedEvent
     * @param <T>
     */
    public static <T> void run(DelayedEvent<T> delayedEvent, Supplier supplier){
        // 安装相关的DelayedEvent数据对象操作
        queue.add(delayedEvent);
        // 启动消费线程 消费添加到延时队列中的消息，前提是任务到了延期时间
        exec.execute(new DataMonitor(queue) {
            @Override
            public void execute(DelayedEvent take) {
                log.info("执行器执行操作:{}",take.getBody());
            }
        });
    }

}
